﻿using DefaultDspPlugins.UI.Common.Modulizer.Engine.GUI;
using DefaultDspPlugins.UI.Common.Modulizer.Engine.GUIv2.Controls;
using SharpDepend.Datatypes;
using SharpDepend.Storage;
using SoundEngine3.DspPlugins.Meta;
using System;
using System.Collections.Generic;
using ZquenceStudio3.Core.Components.Calculator;
using ZquenceStudio3Host.DspHost;
using ZquenceStudio3Host.DspPlugins.Synthesizers.Nodesizer;
using ZquenceStudio3Host.DspPlugins.Synthesizers.Nodesizer.Engine;
using ZquenceStudio3Host.DspPlugins.Synthesizers.Nodesizer.Engine.Modules.Container;
using ZquenceStudio3Host.Graphics;
using ZquenceStudio3Host.Graphics.Components;
using ZquenceStudio3Host.Graphics.Components.Interfaces;
using ZquenceStudio3Host.Graphics.EntityProperties;
using ZquenceStudio3Host.Graphics.GUI;

namespace DefaultDspPlugins.UI.Common.Modulizer.Engine.GUIv2.FrontEndComponents
{
    public class ModuleUIPanel : Panel // TexturePanel
    {
        private const int PANEL_TEXTURE_WIDTH = 256;
        private const int PANEL_TEXTURE_HEIGHT = 256;
        
        private static CalculatorEngine mExpressionEngine = new CalculatorEngine(PANEL_TEXTURE_WIDTH * PANEL_TEXTURE_HEIGHT);
        private static double[] mExpressionResults = new double[PANEL_TEXTURE_WIDTH * PANEL_TEXTURE_HEIGHT];
        private static double[] mXValues = new double[PANEL_TEXTURE_WIDTH * PANEL_TEXTURE_HEIGHT];
        private static double[] mYValues = new double[PANEL_TEXTURE_WIDTH * PANEL_TEXTURE_HEIGHT];
        private string mLastR;
        private string mLastG;
        private string mLastB;
        private bool mFirstInit;
        private ModulizerUIv2 mModulizerUI;

        public BaseModuleUI ModuleUI { get; private set; }

        public BaseModule Module { get { return ModuleUI.Module; } }
        
        public ModuleUIPanel(BasicGuiManager engineCore, BaseModuleUI moduleUI, ModulizerUIv2 modulizerUI)
            : base(engineCore, false)
            //: base(engineCore, PANEL_TEXTURE_WIDTH, PANEL_TEXTURE_HEIGHT, false)
        {
            DimensionInProcent = true;
            ModuleUI = moduleUI;
            mModulizerUI = modulizerUI;

            LoadStructure();

            InvalidateExpression();

            UpdateUIModuleParameterConnections();
        }

        public void SaveStructure()
        {
            // Can be false if Panel is showing in edit mode. But it must be true when it will be saved.
            bool tmp = this.DimensionInProcent;
            this.DimensionInProcent = true;

            CustomNode outputToString = new CustomNode();
            EngineCore.Save(this, outputToString);

            this.DimensionInProcent = tmp;

            ModuleUI.SerializedLayout = outputToString.Nodes[0];
        }

        public void LoadStructure()
        {
            if (!mFirstInit)
            {
                mFirstInit = true;
            }
            else
            {
                // Don't call this first time.
                ModuleUI.RaiseOnUIDestroyed(this);
            }

            ModuleUI.DoLayout(); // TODO: Problem när vi ändrar UI i editorn. Den resetar allt.
            CustomNode serialized = ModuleUI.SerializedLayout;

            bool tmp = BaseObject.AutoRenameNames;
            BaseObject.AutoRenameNames = true;
            this.ClearComponents();
            this.ClearParts();
            EngineCore.LoadUICodeToPanel(serialized, this, false, true);
            BaseObject.AutoRenameNames = tmp;

            UpdateUIModuleParameterConnections();

            ModuleUI.RaiseOnUICreated(this);
            Refresh();
        }

        public void Refresh()
        {
            this.ModuleUI.Refresh();
        }

        public void InvalidateExpression()
        {
            try
            {
                if (ModuleUI.Background.R.Length > 0 && ModuleUI.Background.G.Length > 0 && ModuleUI.Background.B.Length > 0)
                {
                    BackgroundColor = new Color(
                         double.Parse(ModuleUI.Background.R),
                         double.Parse(ModuleUI.Background.G),
                         double.Parse(ModuleUI.Background.B),
                         0.3);
                }
            }
            catch (Exception)
            {
                BackgroundColor = new Color(
                        1,
                        1,
                        1,
                        0.3);
            }

            //try
            //{
            //    BeginEdit();
            //
            //    if (ModuleUI.Background.R != mLastR)
            //    {
            //        if (ModuleUI.Background.R != mExpressionEngine.Expression)
            //        {
            //            mLastR = ModuleUI.Background.R;
            //            mExpressionEngine.Expression = ModuleUI.Background.R;
            //            mExpressionEngine.GetResults(mExpressionResults);
            //        }
            //        for (int i = 0; i < ManipulateTexturePixels.Length; i++)
            //        {
            //            Color pixel = new Color(ManipulateTexturePixels[i]);
            //            pixel.R = (byte)(Math.Min(255, mExpressionResults[i] * 255.0));
            //            pixel.A = 255;
            //            ManipulateTexturePixels[i] = pixel.PacketSigned;
            //        }
            //    }
            //
            //    if (ModuleUI.Background.G != mLastG)
            //    {
            //        if (ModuleUI.Background.G != mExpressionEngine.Expression)
            //        {
            //            mLastG = ModuleUI.Background.G;
            //            mExpressionEngine.Expression = ModuleUI.Background.G;
            //            mExpressionEngine.GetResults(mExpressionResults);
            //        }
            //        for (int i = 0; i < ManipulateTexturePixels.Length; i++)
            //        {
            //            Color pixel = new Color(ManipulateTexturePixels[i]);
            //            pixel.G = (byte)(Math.Min(255, mExpressionResults[i] * 255.0));
            //            pixel.A = 255;
            //            ManipulateTexturePixels[i] = pixel.PacketSigned;
            //        }
            //    }
            //
            //    if (ModuleUI.Background.B != mLastB)
            //    {
            //        if (ModuleUI.Background.B != mExpressionEngine.Expression)
            //        {
            //            mLastB = ModuleUI.Background.B;
            //            mExpressionEngine.Expression = ModuleUI.Background.B;
            //            mExpressionEngine.GetResults(mExpressionResults);
            //        }
            //        for (int i = 0; i < ManipulateTexturePixels.Length; i++)
            //        {
            //            Color pixel = new Color(ManipulateTexturePixels[i]);
            //            pixel.B = (byte)(Math.Min(255, mExpressionResults[i] * 255.0));
            //            pixel.A = 255;
            //            ManipulateTexturePixels[i] = pixel.PacketSigned;
            //        }
            //    }
            //}
            //catch (Exception error)
            //{
            //}
            //finally
            //{
            //    EndEdit();
            //}
        }

        /// <summary>
        /// Find all parameters in the UI and connect it to the right dsp parameter.
        /// </summary>
        void UpdateUIModuleParameterConnections()
        {
            List<BaseObject> parameters = GetComponentsByProperty(BaseModulizerControl.PropertyDspParameter);

            foreach (var parameter in parameters)
            {
                IMinMaxValueControl control = (IMinMaxValueControl)parameter;

                // Get the parameter index from the visible parameters.
                EntityProperty value = parameter.GetProperty(BaseModulizerControl.PropertyDspParameter);
                int parameterIndex = (int)value.GetValue();

                if (parameterIndex > -1)
                {
                    // If module is a group. Get the visible parameters.
                    IList<ParameterProperties> properties = Module.Parameters;
                    if (Module is GroupModule)
                    {
                        properties = (Module as GroupModule).GetVisibleParameters();
                    }

                    if (parameterIndex >= properties.Count)
                    {
                        SharpDepend.Manager.DialogManager.Show("Parameter index '" + parameterIndex + "'  was out of index.", "Error", SharpDepend.DialogIcon.Warning);
                    }
                    else
                    {
                        ParameterProperties nativeParameter = properties[parameterIndex];

                        control.Tag = nativeParameter;
                        control.MinValue = nativeParameter.MinValue;
                        control.MaxValue = nativeParameter.MaxValue;
                        control.Value = nativeParameter.RawValue;
                        
                        control.OnValueChanged -= Control_OnValueChanged; // Make sure that we dont add duplicated delegates.
                        control.OnValueChanged += Control_OnValueChanged;

                        if (control is IDspControl)
                        {
                            (control as IDspControl).SetParameter(nativeParameter, mModulizerUI, Module);
                        }
                    }
                }
            }
        }

        private void Control_OnValueChanged(object sender, double value)
        {
            IMinMaxValueControl control = sender as IMinMaxValueControl;

            (control.Tag as ParameterProperties).RawValue = value;
        }

        static ModuleUIPanel()
        {
            for (int i = 0; i < mXValues.Length; i++)
            {
                mXValues[i] = i % PANEL_TEXTURE_WIDTH;
                mYValues[i] = i / PANEL_TEXTURE_WIDTH;
            }
            mExpressionEngine['X'] = mXValues;
            mExpressionEngine['Y'] = mYValues;
            
            DefinedProperties.AddProperty("ExpR", new EntityString<ModuleUIPanel>(BaseObject_Set_ExpR, BaseObject_Get_ExpR));
            DefinedProperties.AddProperty("ExpG", new EntityString<ModuleUIPanel>(BaseObject_Set_ExpG, BaseObject_Get_ExpG));
            DefinedProperties.AddProperty("ExpB", new EntityString<ModuleUIPanel>(BaseObject_Set_ExpB, BaseObject_Get_ExpB));
            DefinedProperties.AddProperty("Row", new EntityInteger<ModuleUIPanel>(BaseObject_Set_Row, BaseObject_Get_Row));
            DefinedProperties.AddProperty("RowSpan", new EntityInteger<ModuleUIPanel>(BaseObject_Set_RowSpan, BaseObject_Get_RowSpan));
            DefinedProperties.AddProperty("Column", new EntityInteger<ModuleUIPanel>(BaseObject_Set_Column, BaseObject_Get_Column));
            DefinedProperties.AddProperty("ColumnSpan", new EntityInteger<ModuleUIPanel>(BaseObject_Set_ColumnSpan, BaseObject_Get_ColumnSpan));

            DefinedProperties.IgnoreProperty(typeof(ModuleUIPanel), BaseObject.PropertyName);
            DefinedProperties.IgnoreProperty(typeof(ModuleUIPanel), BaseObject.PropertyTagName);
            DefinedProperties.IgnoreProperty(typeof(ModuleUIPanel), BaseObject.PropertyVisible);
            DefinedProperties.IgnoreProperty(typeof(ModuleUIPanel), BaseObject.PropertyPosition);
            DefinedProperties.IgnoreProperty(typeof(ModuleUIPanel), BaseObject.PropertyRotation);
            DefinedProperties.IgnoreProperty(typeof(ModuleUIPanel), BaseObject.PropertyScale);
            DefinedProperties.IgnoreProperty(typeof(ModuleUIPanel), Panel.PropertyDimensionProcent);
        }

        static void BaseObject_Set_ExpR(ModuleUIPanel obj, string value)
        {
            obj.ModuleUI.Background.R = value;
            obj.InvalidateExpression();
        }
        static string BaseObject_Get_ExpR(ModuleUIPanel obj)
        {
            return obj.ModuleUI.Background.R;
        }

        static void BaseObject_Set_ExpG(ModuleUIPanel obj, string value)
        {
            obj.ModuleUI.Background.G = value;
            obj.InvalidateExpression();
        }
        static string BaseObject_Get_ExpG(ModuleUIPanel obj)
        {
            return obj.ModuleUI.Background.G;
        }

        static void BaseObject_Set_ExpB(ModuleUIPanel obj, string value)
        {
            obj.ModuleUI.Background.B = value;
            obj.InvalidateExpression();
        }
        static string BaseObject_Get_ExpB(ModuleUIPanel obj)
        {
            return obj.ModuleUI.Background.B;
        }

        static void BaseObject_Set_Row(ModuleUIPanel obj, int value)
        {
            obj.ModuleUI.Row = value;
        }
        static int BaseObject_Get_Row(ModuleUIPanel obj)
        {
            return obj.ModuleUI.Row;
        }
        static void BaseObject_Set_RowSpan(ModuleUIPanel obj, int value)
        {
            obj.ModuleUI.RowSpan = value;
        }
        static int BaseObject_Get_RowSpan(ModuleUIPanel obj)
        {
            return obj.ModuleUI.RowSpan;
        }

        static void BaseObject_Set_Column(ModuleUIPanel obj, int value)
        {
            obj.ModuleUI.Column = value;
        }
        static int BaseObject_Get_Column(ModuleUIPanel obj)
        {
            return obj.ModuleUI.Column;
        }
        static void BaseObject_Set_ColumnSpan(ModuleUIPanel obj, int value)
        {
            obj.ModuleUI.ColumnSpan = value;
        }
        static int BaseObject_Get_ColumnSpan(ModuleUIPanel obj)
        {
            return obj.ModuleUI.ColumnSpan;
        }
    }
}
